#pragma once
#include <iostream>
#include <cstdio>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define N 1024 // 定义缓冲区大小

// 定义日志输出方式
#define Screen 1    // 输出到屏幕
#define Onefile 2   // 输出到单个文件
#define Classfile 3 // 按级别输出到不同文件（log.txt.Info、log.txt.Error）

#define LogFile "log.txt" // 定义默认日志文件名
using namespace std;

// 定义日志级别（枚举值，便于区分日志重要程度）
#define Info 0    // 信息级日志（一般通知）
#define Debug 1   // 调试级日志（开发调试用）
#define Warning 2 // 警告级日志（潜在问题）
#define Error 3   // 错误级日志（功能异常）
#define Fatal 4   // 致命级日志（程序崩溃）

class Log
{
private:
    // 将日志写入单个文件
    void printOneFile(const string &logname, const string &logtxt)
    {
        string _logname = path + logname; // 拼接完整路径（如./log/log.txt）
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd < 0)
        {
            return;
        }
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }
    // 将日志分类写入文件
    void printClassFile(int level, const string &logtxt)
    {
        string filename = LogFile;
        filename += ".";
        filename += levelToString(level);
        printOneFile(filename, logtxt);
    }
    // 根据输出方式打印日志
    void printLog(int level, const string &logtxt)
    {
        switch (printMethod)
        {
        case Screen: // 输出到屏幕
            cout << logtxt << endl;
            break;
        case Onefile: // 输出到单个文件（LogFile）
            printOneFile(LogFile, logtxt);
            break;
        case Classfile: // 按级别输出到不同文件
            printClassFile(level, logtxt);
            break;
        default: // 未知方式，不处理
            break;
        }
    }
    // 将日志级别（整数）转换为字符串（便于日志显示）
    string levelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "None";
        }
    }

public:
    // 初始化日志输出方式和路径
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }
    // 设置/切换日志输出方式
    void Enable(int method)
    {
        printMethod = method;
    }
    // 实现日志格式化
    // 用法示例：Log()(Info, "user %s login", "admin");
    void operator()(int level, const char *format, ...)
    {
        // 1. 获取当前时间并格式化
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);
        char leftbuffer[N];
        snprintf(leftbuffer, sizeof(leftbuffer), "%s %d年%d月%d日%d时%d分%d秒 ", levelToString(level).c_str(),
                 ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        // 2. 处理可变参数（用户自定义内容)
        va_list ap;
        va_start(ap, format);
        char rightbuffer[N];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, ap);
        va_end(ap);

        // 3. 拼接完整日志内容（时间级别+用户内容）
        char logtxt[N * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

        // 4. 根据输出方式打印日志
        printLog(level, logtxt);
    }
    ~Log() {}

private:
    int printMethod; // 日志输出方式（Screen/Onefile/Classfile）
    string path;     // 日志文件存储路径（默认./log/）
};
